/************************************************************************
                                                                     
   Xceed Ultimate ListBox for Silverlight                                                                                                                                            
   Copyright (C) 2010 Xceed Software Inc.    
                                                                     
   This program is provided to you under the terms of the GNU General Public  
   License version 2 as published by the Free Software Foundation. 
        
   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY, without even the implied warranty of 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License along 
   with this program, if not, write to the Free Software Foundation, Inc., 
   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

   This program can be provided to you by Xceed Software Inc. under a
   proprietary commercial license agreement for use in non-Open Source
   projects. Visit Xceed.com to find the commercial edition of 
   Xceed Ultimate ListBox for Silverlight.                                    
                                                                      
 **********************************************************************/

using System;
using System.Collections;

namespace Xceed.Silverlight.Data
{
  internal static class ResultsExtensions
  {
    internal static int GetMoveUnit( this MoveAndFetchResult moveResult )
    {
      return DataUtils.GetUnit( moveResult.ExpectedMoveCount );
    }

    internal static int GetFetchUnit( this MoveAndFetchResult fetchResult )
    {
      return DataUtils.GetUnit( fetchResult.ExpectedFetchCount );
    }

    internal static Nullable<long> GetMoveDisplacement( this MoveAndFetchResult moveResult )
    {
      return moveResult.ActualMoveCount;
    }

    internal static int GetFetchDisplacement( this MoveAndFetchResult moveAndFetchResult )
    {
      return ResultsExtensions.GetFetchDisplacement( 
        moveAndFetchResult.FetchedObjects, 
        moveAndFetchResult.ExpectedFetchCount );
    }

    internal static int GetFetchDisplacement( this GroupFetchResult groupFetchResult, int expectedFetchCount  )
    {
      return ResultsExtensions.GetFetchDisplacement( 
        DataUtils.ConvertToNonGeneric<DataPath>( groupFetchResult.FetchedItems),
        expectedFetchCount );
    }

    internal static int GetFetchDisplacement( ICollection fetchedObjects, int expectedFetchCount )
    {
      int fetchMove = 0;

      if( fetchedObjects != null )
      {
        int fetchUnit = DataUtils.GetUnit( expectedFetchCount );

        fetchMove = Math.Max( 0, fetchedObjects.Count - 1 ) * fetchUnit;

        if( fetchedObjects.Count != Math.Abs(expectedFetchCount) )
        {
          //This means that the fetch ended out of bound, where there is no data.
          fetchMove += fetchUnit;
        }
      }

      return fetchMove;
    }

    internal static EstimateInt64 GetMaximumFetchCount( this JumpMoveAndFetchResult jumpResult )
    {
      if( jumpResult.FetchedObjects == null )
        return null;

      if( jumpResult.ExpectedFetchCount == 0 )
        return null;

      if( jumpResult.FetchedObjects.Count < Math.Abs( jumpResult.ExpectedFetchCount ) )
        return new EstimateInt64( jumpResult.FetchedObjects.Count * jumpResult.GetFetchUnit(), false );

      EstimateInt64 limitOffset = null;

      if( jumpResult.EndPositionOffset != null )
      {
        ReferencePoint neededReferencePoint = ( jumpResult.GetFetchUnit() == 1 )
        ? ReferencePoint.AfterLast
        : ReferencePoint.BeforeFirst;

        if( jumpResult.EndPositionOffset.ReferencePosition == neededReferencePoint )
        {
          limitOffset = jumpResult.EndPositionOffset.Value;
        }
        else if( jumpResult.TotalCount != null )
        {
          limitOffset = jumpResult.TotalCount - jumpResult.EndPositionOffset.Value;
          limitOffset += 1;
        }

        long maximumFetchCount = Math.Abs( jumpResult.ExpectedFetchCount ) + ( limitOffset.Value - 1 );

        return new EstimateInt64( maximumFetchCount * jumpResult.GetFetchUnit(), limitOffset.IsEstimate );
      }

      return null;
    }

    internal static EstimateInt64 GetTotalDisplacement( this MoveAndFetchResult moveAndFetchResult )
    {

      //A "null" moveDisplacement indicates a failed move operation with no information
      //on how much of the move succeeded. We use ExpectedMoveCount as the worst case scenario.
      //Zero could infer a shorter data source than expected.
      Nullable<long> moveDisplacement = moveAndFetchResult.GetMoveDisplacement();
      int fetchDisplacement = moveAndFetchResult.GetFetchDisplacement();

      if( moveDisplacement == null )
      {
        return new EstimateInt64( moveAndFetchResult.ExpectedMoveCount + fetchDisplacement, true );
      }
      else
      {
        return new EstimateInt64( moveDisplacement.Value + fetchDisplacement, moveAndFetchResult.ApproximateMove );
      }
    }

    internal static  JumpMoveAndFetchParameters GetParameters(this JumpMoveAndFetchResult result)
    {
      return new JumpMoveAndFetchParameters(result.SourcePosition, result.ExpectedMoveCount, result.ExpectedFetchCount, result.ApproximateMove);
    }


    internal static bool IsMovingForward( this MoveAndFetchResult fetchResult )
    {
      if( fetchResult.ExpectedMoveCount == 0 )
        throw new InvalidOperationException( "No moves were made with this operation." );

      return ( fetchResult.ExpectedMoveCount > 0 );
    }

    internal static bool IsFetchingForward( this MoveAndFetchResult fetchResult )
    {
      if( fetchResult.ExpectedFetchCount == 0 )
        throw new InvalidOperationException( "No fetches were made with this operation." );

      return ( fetchResult.ExpectedFetchCount > 0 );
    }

    internal static bool IsMoveSuccess( this MoveAndFetchResult moveAndFetchResult )
    {
      return ( moveAndFetchResult.FetchedObjects != null );
    }

    internal static bool IsFetchSuccess( this MoveAndFetchResult moveAndFetchResult )
    {
      return ( moveAndFetchResult.FetchedObjects != null 
        && moveAndFetchResult.FetchedObjects.Count == moveAndFetchResult.ExpectedFetchCount);
    }
  }
}
